#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <string>
#include <unistd.h>
#include <cerrno>
#include <sys/wait.h>
#include<signal.h>
#include<pthread.h>
// #include<sys/types.h>

#include "Log.hpp"
#include "InetAddr.hpp"
#include "common.hpp"
#define backlog 8

using namespace LogMudule;
class tcpServer
{
    const static uint16_t gport = 8081;

public:
    tcpServer(uint16_t port = gport)
        : _port(port)
    {
    }
    ~tcpServer()
    {
    }
    bool initServer()
    {
        _listenSockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listenSockfd < 0)
        {
            // zdl: 这个地方就需要将日志文件调进来
            LOG(LogLevel::FATAL) << "socket create fail!!";
            die(socket_error);
        }
        LOG(LogLevel::INFO) << "socket create success!! sockfd is :" << _listenSockfd;

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port); // 服务器的端口号是必须的 // htons (主机转网络)
        local.sin_addr.s_addr = INADDR_ANY;
        // 2. bind
        int n = ::bind(_listenSockfd, conv(&local), sizeof(local));
        if (n < 0)
        {
            // zdl: 这个地方就需要将日志文件调进来
            LOG(LogLevel::FATAL) << "bind create fail!!";
            die(bind_error);
        }
        LOG(LogLevel::INFO) << "bind create success!! sockfd is :" << _listenSockfd;

        // 3. cs tcp 时面向连接的， 就要求tcp随时等待链接
        // zdl::需要将tcp设置为监听状态
        n = ::listen(_listenSockfd, backlog);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen create fail!!";
            die(listen_error);
        }
        LOG(LogLevel::INFO) << "listen create success!! sockfd is :" << _listenSockfd;
        ::signal(SIGCHLD, SIG_IGN); //zdl:: 子进程直接退出不需要进行wait os 会自动回收资源
        return true;
    }

    void handlerRequest(int sockfd) // tcp也是全双工通信
    {
        char inbuffer[4096];
        while (true)
        {
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                inbuffer[n] = 0;
                std::string echo_str = "server say#";
                echo_str += inbuffer;

                ::write(sockfd, echo_str.c_str(), echo_str.size());
            }
            else if (!n)
            {
                // read如果读取到返回为0， 表示client退出
                LOG(LogLevel::INFO) << "client quit!!" << sockfd;
                break;
            }
            else
                break;
        }
        ::close(sockfd);
        LOG(LogLevel::INFO) << "close sockfd:" << sockfd;
    }
    void start()
    {
        _isRunning = true;
        while (_isRunning)
        {
            // 不能独居数据
            // 需要现在获取新链接
            // zdl:: 1.获取新链接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof (peer); // 这个地方哟定要注意，要不然会出新问题
            LOG(LogLevel::INFO) << "wait for client connect...";
            // zdl:: 2. accept
            int sockfd = ::accept(_listenSockfd, conv(&peer), &peerlen);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);
                continue;
            }
            // 获取链接成功
            LOG(LogLevel::INFO) << "accept success, scokfd is:" << sockfd;

            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "client info is " << addr.Addr();
            // version -0
            // handlerRequest(sockfd);

            // // version -1 多进程版本
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     // child
            //     // question one: 子进程会继承父进程的文件描述表，两张父子各一张
            //     // 紫荆城需要关闭不需要的文件描述符
            //     ::close(_listenSockfd);
            //     if (fork() > 0)
            //     {
            //         // 让子进程退出
            //         exit(0);
            //     }
            //     //此时就是孙子进程 -》 孤儿进程 -》 1
            //     handlerRequest(_listenSockfd);
            //     exit(0);
            // }

            // ::close(sockfd);
            // // int rid = ::waitpid(pid, nullptr, 0);
            // // if (rid < 0)
            // // {
            // //     LOG(LogLevel::WARNING) << "waitpid error: " << strerror(errno);
            // // }
            // zdl:: 多线程版本
            pthread_t tid;
            // pthread_create(&tid, nullptr, handlerRequest, );
        }
    }
    void stop()
    {
        _isRunning = false;
    }

private:
    int _listenSockfd;
    uint16_t _port;
    bool _isRunning;
};

// zdl::herad you loud and clear